/*
 * Copyright (C) 2001-2005 Pleasant nightmare studio
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.pleasantnightmare.noraxidium.util;

import org.apache.log4j.Logger;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.util.Date;
import java.util.Properties;

/**
 * A dialog that allows showing error to the user, allows easy copy/pasting of stacktrace, and potentially
 * adds ability to mail it to the devs.
 *
 * @author deus
 * @version 1.0
 * @since Jul 6, 2010 3:32:40 PM
 */
public class CrashWindow extends JFrame {
  private static final Logger LOGGER = Logger.getLogger(CrashWindow.class);
  private static final Dimension PREFERRED_SIZE = new Dimension(550, 350);
  private static final String CRASH_MAIL_RECEPIENT = "noraxidium@gmail.com";
  private static final String USERNAME = "noraxidium@gmail.com";
  private static final String PASSWORD = "a cyberpunk stealth game";
  private static final String SMTP_SERVER = "smtp.gmail.com";
  private static final String SMTP_PORT = "465";
  private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";

  private String errorMessage;
  private String stacktrace;

  public CrashWindow(String errorMessage, String stacktrace) {
    this.errorMessage = errorMessage;
    this.stacktrace = stacktrace;
    layoutComponents();

    setTitle("Application crash!");
    addWindowListener(new WindowAdapter() {
      @Override public void windowDeactivated(WindowEvent e) {
        CrashWindow.this.dispose();
      }
    });
    setPreferredSize(PREFERRED_SIZE);

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Point screenCenter = new Point(
        (screenSize.width - PREFERRED_SIZE.width) / 2,
        (screenSize.height - PREFERRED_SIZE.height) / 2
    );
    setLocation(screenCenter);
    pack();
  }

  private void layoutComponents() {
    JPanel contentPane = new JPanel();
    contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));

    JLabel messageLabel = new JLabel(errorMessage);
    JTextArea stacktraceText = new JTextArea(stacktrace);
    stacktraceText.setEditable(false);
    JScrollPane stacktraceScroll = new JScrollPane(stacktraceText);

    JPanel buttonPane = createButtonPanel();

    contentPane.add(messageLabel);
    contentPane.add(stacktraceScroll);
    contentPane.add(buttonPane);
    setContentPane(contentPane);
  }

  private JPanel createButtonPanel() {
    JPanel buttonPanel = new JPanel();
    buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
    buttonPanel.setPreferredSize(new Dimension(175, 50));

    final JButton mailDevsButton = new JButton("Mail devs");
    mailDevsButton.addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        try {
          Properties props = new Properties();
          props.put("mail.smtp.host", SMTP_SERVER);
          props.put("mail.smtp.auth", "true");
          props.put("mail.debug", "false");
          props.put("mail.smtp.port", SMTP_PORT);
          props.put("mail.smtp.socketFactory.port", SMTP_PORT);
          props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
          props.put("mail.smtp.socketFactory.fallback", "false");

          Session session = Session.getDefaultInstance(props, new Authenticator() {
            @Override protected PasswordAuthentication getPasswordAuthentication() {
              return new PasswordAuthentication(USERNAME, PASSWORD);
            }
          });

          InternetAddress localUser = getLocalUser(session);

          // Construct the message
          Message msg = new MimeMessage(session);
          msg.setFrom(localUser);
          msg.setRecipient(Message.RecipientType.TO, new InternetAddress(CRASH_MAIL_RECEPIENT));
          msg.setSubject("[crash] " + errorMessage + " - " + DateFormat.getInstance().format(new Date(System.currentTimeMillis())));
          msg.setText(stacktrace);

          // Send the message
          Transport.send(msg);
        } catch (AddressException e1) {
          LOGGER.fatal("Failed at sending mail to the dev!", e1);
        } catch (MessagingException e1) {
          LOGGER.fatal("Failed at sending mail to the dev!", e1);
        }

        mailDevsButton.setEnabled(false);
        mailDevsButton.setText("Mail sent! Thanks!");
      }

      private InternetAddress getLocalUser(Session session) throws AddressException {
        InternetAddress localUser = InternetAddress.getLocalAddress(session);
        if (localUser == null)
          localUser = new InternetAddress(System.getProperty("user.home") + "@" + "unknown.unk");
        return localUser;
      }
    });

    JButton closeButton = new JButton("Close");
    closeButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CrashWindow.this.dispose();
      }
    });

    buttonPanel.add(Box.createHorizontalGlue());
    buttonPanel.add(mailDevsButton);
    buttonPanel.add(Box.createHorizontalGlue());
    buttonPanel.add(closeButton);
    buttonPanel.add(Box.createHorizontalGlue());

    return buttonPanel;
  }
}
